using System;
using Ease.EaseNode.Runtime;
using Ease.EaseNode.Runtime.Param;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;

namespace Ease.EaseNode.Editor.NodeView
{
    public abstract class BaseEaseNode : Node, IEaseNode
    {
        public IEaseNodeDataState State { get; set; }
        public string Key { get; set; }

        /// <summary>
        /// 点击该节点时被调用的事件，比如转发该节点信息到Inspector中显示
        /// </summary>
        public event Action<BaseEaseNode> OnNodeSelected;

        protected BaseEaseNode(IEaseNodeDataState state) : base()
        {
            State = state;
            Key = State.Key;
            foreach (var dataInputConfig in state.InputConfigs)
            {
                Port input = GetPortForNode(this, Direction.Input, dataInputConfig.capacity);
                input.name = dataInputConfig.CreateName("input", Key);
                input.portName = dataInputConfig.portName;
                input.portColor = dataInputConfig.capacity == Port.Capacity.Single
                    ? EaseNodeConst.PortSingleColor
                    : EaseNodeConst.PortMultiColor;
                inputContainer.Add(input);
            }

            foreach (var dataOutPutConfig in state.OutputConfigs)
            {
                Port outPort = GetPortForNode(this, Direction.Output, dataOutPutConfig.capacity);
                outPort.name = dataOutPutConfig.CreateName("output", Key);
                outPort.portName = dataOutPutConfig.portName;
                outPort.portColor = dataOutPutConfig.capacity == Port.Capacity.Single
                    ? EaseNodeConst.PortSingleColor
                    : EaseNodeConst.PortMultiColor;
                outputContainer.Add(outPort);
            }
        }

        // 为节点n创建input port或者output port
        // Direction: 是一个简单的枚举，分为Input和Output两种
        protected Port GetPortForNode(BaseEaseNode n, Direction portDir, Port.Capacity capacity = Port.Capacity.Single)
        {
            // Orientation也是个简单的枚举，分为Horizontal和Vertical两种，port的数据类型是bool
            return n.InstantiatePort(Orientation.Horizontal, portDir, capacity, typeof(bool));
        }

        //告诉Inspector去绘制该节点
        public override void OnSelected()
        {
            Debug.Log($"{this.name}节点被点击");
            base.OnSelected();
            OnNodeSelected?.Invoke(this);
            if (this.GetPosition().position != Vector2.zero)
                State.NodePos = this.GetPosition().position;
        }

        public virtual void OnNodeCreate(Vector2 pos)
        {
            State.OnValueChangeEvent += OnStateChange;
            State.NodePos = pos;
        }

        public virtual void OnNodeRemove()
        {
            State.OnValueChangeEvent -= OnStateChange;
            State = null;
        }

        public virtual void OnEdgeCreate(Edge edge)
        {
            var inputName = edge.input.name;
            var outputName = edge.output.name;
            if (edge.input.node is BaseEaseNode easeNode1)
            {
                easeNode1.State.AddInputInfos(inputName, outputName);
            }

            if (edge.output.node is BaseEaseNode easeNode2)
            {
                easeNode2.State.AddOutputInfos(outputName, inputName);
            }
        }

        public virtual void OnEdgeRemove(Edge edge)
        {
            var inputName = edge.input.name;
            var outputName = edge.output.name;
            if (edge.input.node is BaseEaseNode easeNode1)
            {
                easeNode1.State.RemoveInputInfos(inputName, outputName);
            }

            if (edge.output.node is BaseEaseNode easeNode2)
            {
                easeNode2.State.RemoveOutputInfos(outputName, inputName);
            }
        }


        protected abstract void OnStateChange(BaseChangeParam param);
    }
}